home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / Source / Macintosh Tracker Source / Tracker Client Folder / Core 18⁄March⁄1994 / Profiler Stuff / Profiler.c next >
Encoding:
C/C++ Source or Header  |  1993-01-04  |  5.4 KB  |  288 lines  |  [TEXT/KAHL]

  1. #if __option(profile)
  2.  
  3. /*
  4.  *  profile.c
  5.  *
  6.  *  Copyright (c) 1991 Symantec Corporation.  All rights reserved.
  7.  *
  8.  */
  9.  
  10. /* Warning:  This file has been modified to suit my purposes! */
  11.  
  12. #pragma options(!profile)
  13.  
  14. #include "stdio.h"
  15. #include "limits.h"
  16. #include "stdlib.h"
  17. #include "string.h"
  18. #include "Profiler.h"
  19.  
  20. /*
  21.  *  #define _VIATIMER_ to use VIA ticks rather than clock ticks.
  22.  *
  23.  *  Clock ticks occur 60 times a second, whereas VIA ticks occur
  24.  *  approximately 780,000 times a second.  Therefore VIA ticks yield
  25.  *  a more accurate profile, though they are more sensitive to
  26.  *  interrupt-level activity.  Also the VIA timer is used by the
  27.  *  Sound Driver, and therefore may conflict with some programs.
  28.  *
  29.  */
  30.  
  31. #ifdef _VIATIMER_
  32. #define Ticks    VIA_ticks()
  33. #endif
  34.  
  35. /*  symbol table entry  */
  36. static struct sym {
  37.     unsigned char    *fname;
  38.     long            count;
  39.     long            total;
  40.     long            min;
  41.     long            max;
  42. } *syms;
  43.  
  44. /*  stack entry  */
  45. static struct stack {
  46.     struct sym        *sym;
  47.     void            **ret;
  48.     long            start;
  49.     long            overhead;
  50. } *stack;
  51.  
  52. int _profile, _trace;
  53. static unsigned nsyms, depth, max_nsyms, max_depth;
  54.  
  55. void _profile_(unsigned char *);
  56. static struct sym *lookup(unsigned char *);
  57. static void *profile_exit(void);
  58. static void done(void);
  59. static int compare(const void *, const void *);
  60.  
  61.  
  62. /*
  63.  *  InitProfile
  64.  *
  65.  *  This must be called once to initialize the profiler.  The arguments
  66.  *  specify the maximum number of functions to be profiled, and the
  67.  *  maximum number of nested function calls.
  68.  *
  69.  */
  70.  
  71. FILE*    tracefile;
  72.  
  73. void
  74. InitProfile(unsigned nsyms, unsigned depth)
  75. {
  76.     if (syms = malloc(nsyms * (long) sizeof(struct sym)))
  77.         max_nsyms = nsyms;
  78.     if (stack = malloc(depth * (long) sizeof(struct stack)))
  79.         max_depth = depth;
  80.     _profile = true;
  81. /*    _trace = true; */
  82.     if (_trace)
  83.         tracefile = fopen(" Trace Dump","w");
  84. }
  85.  
  86.  
  87. /*
  88.  *  _profile_ - profiler entry point
  89.  *
  90.  *  Each function compiled with the "Profile" option begins with a call
  91.  *  to _profile_("\pfuncname").
  92.  *
  93.  */
  94.  
  95. void
  96. _profile_(unsigned char *fname)
  97. {
  98.     register struct sym *p;
  99.     register struct stack *q;
  100.     long start;
  101.     int tracing;
  102.     
  103.     if (_profile && depth < max_depth) {
  104.         start = Ticks;
  105.         tracing = _trace;
  106.         _profile = _trace = false;
  107.         if (p = lookup(fname)) {
  108.             if (tracing)
  109.                 fprintf(tracefile,"%*s%#s\n", depth, "", fname);
  110.             ++p->count;
  111.             q = &stack[depth++];
  112.             q->sym = p;
  113.             asm {
  114.                 movea.l    (a6),a0
  115.                 move.l    4(a0),q->ret
  116.                 lea        @exit,a1
  117.                 move.l    a1,4(a0)
  118.             }
  119.             q->start = start;
  120.             q->overhead = Ticks - start;
  121.         }
  122.         _profile = true;
  123.         _trace = tracing;
  124.     }
  125.     return;
  126.  
  127.         /*  the profiled function will return here  */
  128.         
  129. exit:
  130.     asm {
  131.         move.l    d0,-(sp)        ;  preserve result
  132.         jsr        profile_exit
  133.         movea.l    d0,a0            ;  real return address
  134.         move.l    (sp)+,d0        ;  restore result
  135.         jmp        (a0)            ;  return
  136.     }
  137. }
  138.  
  139.  
  140. /*
  141.  *  profile_exit
  142.  *
  143.  *  "_profile_" arranges for this routine to be called as each profiled
  144.  *  function returns.
  145.  *
  146.  */
  147.  
  148. static void *
  149. profile_exit(void)
  150. {
  151.     register struct stack *q = &stack[--depth];
  152.     register struct sym *p = q->sym;
  153.     register long gross = Ticks - q->start;
  154.     register long net = gross - q->overhead;
  155.  
  156.     if (net < 0)
  157.         net = 0;
  158.     if (p->max < net)
  159.         p->max = net;
  160.     if (p->min > net)
  161.         p->min = net;
  162.     p->total += net;
  163.     if (depth)
  164.         q[-1].overhead += gross;
  165.     return(q->ret);
  166. }
  167.  
  168.  
  169. /*
  170.  *  lookup - get the symbol table entry for the current function
  171.  *
  172.  */
  173.  
  174. static struct sym *
  175. lookup(unsigned char *fname)
  176. {
  177.     register unsigned i = 0, j, n = nsyms;
  178.     register struct sym *p;
  179.     register struct stack *q;
  180.     
  181.     if (n == 0)
  182.         atexit(done);
  183.         
  184.         /*  binary search  */
  185.         
  186.     while (i < n) {
  187.         j = (i + n - 1) >> 1;
  188.         p = &syms[j];
  189.         if (p->fname == fname)
  190.             return(p);
  191.         if (p->fname > fname)
  192.             n = j;
  193.         else
  194.             i = j + 1;
  195.     }
  196.     
  197.         /*  insert new symbol into table  */
  198.         
  199.     if (nsyms == max_nsyms)
  200.         return(NULL);
  201.     p = &syms[i];
  202.     memmove(p + 1, p, (nsyms - i) * (long) sizeof(struct sym));
  203.     p->fname = fname;
  204.     p->count = p->total = p->max = 0;
  205.     p->min = LONG_MAX;
  206.     ++nsyms;
  207.     
  208.         /*  adjust pointer to moved symbols  */
  209.         
  210.     for (q = stack, n = depth; n--; q++) {
  211.         if (q->sym >= p)
  212.             ++q->sym;
  213.     }
  214.     return(p);
  215. }
  216.  
  217.  
  218. /*
  219.  *  DumpProfile - print a report
  220.  *
  221.  *  It is not necessary to call this routine, as it will be called
  222.  *  automatically at program exit.
  223.  *
  224.  */
  225.  
  226. void
  227. DumpProfile(void)
  228. {
  229.     int profiling = _profile, tracing = _trace;
  230.     register unsigned n;
  231.     register struct sym *p;
  232.     register long total = 0;
  233.     FILE*    DumpFile;
  234.  
  235.     DumpFile = fopen(" Profile Dump","w");
  236.     _profile = _trace = false;
  237.     fprintf(DumpFile,"\n%-47s  Minimum  Maximum  Average    %%   Entries\n\n", "Function");
  238.     for (p = syms, n = nsyms; n--; p++)
  239.         total += p->total;
  240.     for (p = syms, n = nsyms; n--; p++) {
  241.         fprintf(DumpFile,"%#-47s%8lu %8lu %8lu   %3u %8lu\n",
  242.                     p->fname,
  243.                     p->min == LONG_MAX ? 0 : p->min,
  244.                     p->max,
  245.                     p->count ? p->total / p->count : 0,
  246.                     total ? (int) (100. * p->total / total) : 0,
  247.                     p->count);
  248.     }
  249.     fclose(DumpFile);
  250.     if (_trace)
  251.         fclose(tracefile);
  252.     _profile = profiling;
  253.     _trace = tracing;
  254. }
  255.  
  256.  
  257. /*
  258.  *  done - print a report automatically at exit
  259.  *
  260.  */
  261.  
  262. static void
  263. done(void)
  264. {
  265.     _profile = _trace = false;
  266.     qsort(syms, nsyms, sizeof(struct sym), compare);
  267.     DumpProfile();
  268. }
  269.  
  270.  
  271. /*
  272.  *  compare - comparison routine for sorting symbols alphabetically
  273.  *
  274.  */
  275.  
  276. static int
  277. compare(const void *P, const void *Q)
  278. {
  279.     register const struct sym *p = P;
  280.     register const struct sym *q = Q;
  281.     int np = p->fname[0], nq = q->fname[0], result;
  282.     
  283.     result = strncmp((char *) &p->fname[1], (char *) &q->fname[1], np < nq ? np : nq);
  284.     return(result ? result : (np - nq));
  285. }
  286.  
  287. #endif
  288.